#ifndef __M_CONNECTION_H__
#define __M_CONNECTION_H__
#include "mq_channel.hpp"

namespace zymq 
{
    class Connection
    {
    public:
        using ptr = std::shared_ptr<Connection>;

        Connection(const muduo::net::TcpConnectionPtr &conn,
                   const ProtobufCodecPtr &codec, const ConsumerManager::ptr &cmp,
                   const VirtualHost::ptr &host, const threadpool::ptr &pool)
            :_conn(conn), _codec(codec), _cmp(cmp), _host(host), _pool(pool), _channels(std::make_shared<ChannelManager>())
        {}

        void openChannel(const openChannelRequestPtr & req)
        {
            bool ret = _channels->openChannel(req->cid(), _conn, _codec, _cmp, _host, _pool);
            if(ret == false)
                basicResponse(false, req->rid(), req->cid());

            return basicResponse(true, req->rid(), req->cid());
        }
        void closeChannel(const closeChannelRequestPtr & req)
        {
            _channels->closeChannel(req->cid());

            return basicResponse(true, req->rid(), req->cid());
        }
        Channel::ptr getChannel(const std::string & cid)
        {
            return _channels->getChannel(cid);
        }
        
    private:
        void basicResponse(bool ok, const std::string &rid, const std::string &cid)
        {
            basicCommonResponse resp;
            resp.set_rid(rid);
            resp.set_cid(cid);
            resp.set_ok(ok);

            _codec->send(_conn, resp);
        }
    private:
        muduo::net::TcpConnectionPtr _conn; // 连接:信道 一：多
        ProtobufCodecPtr _codec; // 解码
        ConsumerManager::ptr _cmp; // 消费者管理句柄
        VirtualHost::ptr _host; // 虚拟机
        threadpool::ptr _pool; // 线程池
        ChannelManager::ptr _channels;
    };

    class ConnectionManager
    {
    public:
        using ptr = std::shared_ptr<ConnectionManager>;

        ConnectionManager(){}

        void newConnection(const muduo::net::TcpConnectionPtr &conn,
                   const ProtobufCodecPtr &codec, const ConsumerManager::ptr &cmp,
                   const VirtualHost::ptr &host, const threadpool::ptr &pool)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_conns.find(conn) != _conns.end()) return;

            Connection::ptr self_conn = std::make_shared<Connection>(conn, codec, cmp, host, pool);
            _conns[conn] = self_conn;
        }
        void delConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);

            _conns.erase(conn);
        }
        Connection::ptr getConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_conns.find(conn) == _conns.end()) return nullptr;

            return _conns[conn];
        }
    private:
        std::mutex _mutex;
        std::unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _conns;
    };
}

#endif